package com.quick.develop.flowable.utils;


import org.apache.commons.lang.StringUtils;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.*;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import static com.quick.develop.flowable.utils.ExpressionUtil.judgeExpression;

/**
 * @author junyuan.liu
 * @description: 
 * @date 2022/6/27 19:34
 */
public class FindNextNodeUtil {

    /** 
     * @description  获取下一节点集合 可能是多个 如果是CallActivity或者其他 统一封装成UserTask
     * @param bpmnModel BpmnModel
     * @param taskDefinitionKey 节点key
     * @param map 分支判断的数据
     * @return java.util.List<org.flowable.bpmn.model.UserTask>
     * @author junyuan.liu
     * @date 2022/6/28 9:37
     */ 
    public static List<UserTask> getNextUserTasks(BpmnModel bpmnModel,String taskDefinitionKey, Map<String, Object> map ){
        List<UserTask> data = new ArrayList<>();
        Process mainProcess = bpmnModel.getMainProcess();
        Collection<FlowElement> flowElements = mainProcess.getFlowElements();
        FlowElement flowElement = bpmnModel.getFlowElement(taskDefinitionKey);
        next(flowElements, flowElement, map, data);
        return data;
    }


    /** 
     * @description  判断下一个节点并填充
     * @param flowElements 全流程的节点集合
     * @param flowElement 当前节点
     * @param map 分支流转判断数据
     * @param data 填装的数据
     * @author junyuan.liu
     * @date 2022/6/28 9:37
     */ 
    public static void next(Collection<FlowElement> flowElements, FlowElement flowElement, Map<String, Object> map, List<UserTask> data) {
        //如果是结束节点
        if (flowElement instanceof EndEvent) {
            //如果是子任务的结束节点
            if (getSubProcess(flowElements, flowElement) != null) {
                flowElement = getSubProcess(flowElements, flowElement);
            }else {
                String name = StringUtils.isNotEmpty(flowElement.getName()) ? flowElement.getName() : "结束";
                UserTask userTask = new UserTask();
                userTask.setId(flowElement.getId());
                userTask.setName(name);
                data.add(userTask);
            }
        }
        //获取Task的出线信息--可以拥有多个
        List<SequenceFlow> outGoingFlows = null;
        if (flowElement instanceof Task) {
            outGoingFlows = ((Task) flowElement).getOutgoingFlows();
        } else if (flowElement instanceof Gateway) {
            outGoingFlows = ((Gateway) flowElement).getOutgoingFlows();
        } else if (flowElement instanceof StartEvent) {
            outGoingFlows = ((StartEvent) flowElement).getOutgoingFlows();
        } else if (flowElement instanceof SubProcess) {
            outGoingFlows = ((SubProcess) flowElement).getOutgoingFlows();
        } else if (flowElement instanceof CallActivity) {
            outGoingFlows = ((CallActivity) flowElement).getOutgoingFlows();
        }
        if (outGoingFlows != null && outGoingFlows.size() > 0) {
            //遍历所有的出线--找到可以正确执行的那一条
            for (SequenceFlow sequenceFlow : outGoingFlows) {
                //1.有表达式，且为true
                //2.无表达式
                String expression = sequenceFlow.getConditionExpression();
                if (expression == null || judgeExpression(map, expression)) {
                    //出线的下一节点
                    String nextFlowElementId = sequenceFlow.getTargetRef();
                    if (checkSubProcess(nextFlowElementId, flowElements, data)) {
                        continue;
                    }

                    //查询下一节点的信息
                    FlowElement nextFlowElement = getFlowElementById(nextFlowElementId, flowElements);
                    //调用流程
                    if (nextFlowElement instanceof CallActivity) {
                        CallActivity ca = (CallActivity) nextFlowElement;
                        if (ca.hasMultiInstanceLoopCharacteristics()) {
                            UserTask userTask = new UserTask();
                            userTask.setId(ca.getId());
                            userTask.setLoopCharacteristics(ca.getLoopCharacteristics());
                            userTask.setName(ca.getName());
                            data.add(userTask);
                        }
                         next(flowElements, nextFlowElement, map, data);
                    }
                    //用户任务
                    if (nextFlowElement instanceof UserTask) {
                        data.add((UserTask) nextFlowElement);
                    }
                    //所有网关
                    else if (nextFlowElement instanceof Gateway) {
                        next(flowElements, nextFlowElement, map, data);
                    }
                    /*//排他网关
                    else if (nextFlowElement instanceof ExclusiveGateway) {
                        next(flowElements, nextFlowElement, map, data);
                    }
                    //并行网关
                    else if (nextFlowElement instanceof ParallelGateway) {
                        next(flowElements, nextFlowElement, map, data);
                    }
                    //包容网关
                    else if (nextFlowElement instanceof InclusiveGateway) {
                        next(flowElements, nextFlowElement, map, data);
                    }*/
                    
                    //接收任务
                    else if (nextFlowElement instanceof ReceiveTask) {
                        next(flowElements, nextFlowElement, map, data);
                    }
                    //服务任务
                    else if (nextFlowElement instanceof ServiceTask) {
                        next(flowElements, nextFlowElement, map, data);
                    }
                    //子任务的起点
                    else if (nextFlowElement instanceof StartEvent) {
                        next(flowElements, nextFlowElement, map, data);
                    }
                    //结束节点
                    else if (nextFlowElement instanceof EndEvent) {
                        next(flowElements, nextFlowElement, map, data);
                    }
                }
            }
        }
    }

    /** 
     * @description  判断是否是多实例子流程并且需要设置集合类型变量
     * @param id 节点ID
     * @param flowElements 全流程的节点集合
     * @param data 填装的数据
     * @return boolean
     * @author junyuan.liu
     * @date 2022/6/27 19:37
     */ 
    public static boolean checkSubProcess(String id, Collection<FlowElement> flowElements, List<UserTask> data) {
        for (FlowElement flowElement1 : flowElements) {
            if (flowElement1 instanceof SubProcess && flowElement1.getId().equals(id)) {

                SubProcess sp = (SubProcess) flowElement1;
                if (sp.getLoopCharacteristics() != null) {
                    UserTask userTask = new UserTask();
                    userTask.setId(sp.getId());
                    userTask.setLoopCharacteristics(sp.getLoopCharacteristics());
                    userTask.setName(sp.getName());
                    data.add(userTask);
                    return true;
                }
            }
        }

        return false;

    }

    /** 
     * @description  查询一个节点的是否子任务中的节点，如果是，返回子任务
     * @param flowElements 全流程的节点集合
     * @param flowElement 当前节点
     * @return org.flowable.bpmn.model.FlowElement
     * @author junyuan.liu
     * @date 2022/6/27 19:36
     */ 
    public static FlowElement getSubProcess(Collection<FlowElement> flowElements, FlowElement flowElement) {
        for (FlowElement flowElement1 : flowElements) {
            if (flowElement1 instanceof SubProcess) {
                for (FlowElement flowElement2 : ((SubProcess) flowElement1).getFlowElements()) {
                    if (flowElement.equals(flowElement2)) {
                        return flowElement1;
                    }
                }
            }
        }
        return null;
    }

    /** 
     * @description  根据ID查询流程节点对象, 如果是子任务，则返回子任务的开始节点
     * @param id ID
     * @param flowElements 节点集合
     * @return org.flowable.bpmn.model.FlowElement
     * @author junyuan.liu
     * @date 2022/6/28 9:22
     */ 
    public static FlowElement getFlowElementById(String id, Collection<FlowElement> flowElements) {
        for (FlowElement flowElement : flowElements) {
            if (flowElement.getId().equals(id)) {
                //如果是子任务，则查询出子任务的开始节点
                if (flowElement instanceof SubProcess) {
                    return getStartFlowElement(((SubProcess) flowElement).getFlowElements());
                }
                return flowElement;
            }
            if (flowElement instanceof SubProcess) {
                FlowElement flowElement1 = getFlowElementById(id, ((SubProcess) flowElement).getFlowElements());
                if (flowElement1 != null) {
                    return flowElement1;
                }
            }
        }
        return null;
    }

    /** 
     * @description  返回流程的开始节点
     * @param flowElements 节点集合
     * @return org.flowable.bpmn.model.FlowElement
     * @author junyuan.liu
     * @date 2022/6/28 9:22
     */ 
    public static FlowElement getStartFlowElement(Collection<FlowElement> flowElements) {
        for (FlowElement flowElement : flowElements) {
            if (flowElement instanceof StartEvent) {
                return flowElement;
            }
        }
        return null;
    }

}
